package io.ganguo.chat.route.server;

import io.ganguo.chat.core.connetion.ConnectionManager;
import io.ganguo.chat.core.connetion.IMConnection;
import io.ganguo.chat.core.handler.IMHandler;
import io.ganguo.chat.core.handler.IMHandlerManager;
import io.ganguo.chat.core.protocol.Commands;
import io.ganguo.chat.core.protocol.Constant;
import io.ganguo.chat.core.protocol.Handlers;
import io.ganguo.chat.core.transport.Header;
import io.ganguo.chat.core.transport.IMRequest;
import io.ganguo.chat.core.transport.IMResponse;
import io.ganguo.chat.core.util.DateUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static io.netty.handler.timeout.IdleState.*;

public class ChatServerHandler extends SimpleChannelInboundHandler<IMRequest> {

    private Logger logger = LoggerFactory.getLogger(ChatServerHandler.class);

    private final ConnectionManager mConnectionManager = ConnectionManager.getInstance();

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);

        mConnectionManager.create(ctx);

        logger.info("handlerAdded " + mConnectionManager.count());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);

        mConnectionManager.remove(ctx);

        logger.info("handlerRemoved " + mConnectionManager.count());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, IMRequest request) throws Exception {
        logger.info("messageReceived header:" + request.getHeader());

        IMConnection conn = mConnectionManager.find(ctx);
        Header header = request.getHeader();

        IMHandler handler = IMHandlerManager.getInstance().find(header.getHandlerId());
        if (handler != null) {
            handler.dispatch(conn, request);
        } else {
            logger.warn("Not found handlerId: " + header.getHandlerId());
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);

        if (evt instanceof IdleStateEvent && ((IdleStateEvent) evt).state().equals(IdleState.ALL_IDLE)) {
            System.out.println("ALL_IDLE");
            ctx.channel().attr(AttributeKey.valueOf(Constant.HEARTBEAT_PINGED)).set(System.currentTimeMillis());

            IMResponse resp = new IMResponse();
            Header header = new Header();
            header.setHandlerId(Handlers.HEARTBEAT);
            header.setCommandId(Commands.CLIENT_HEARTBEAT);
            resp.setHeader(header);
            ctx.channel().writeAndFlush(resp);
        }

        if (evt instanceof IdleStateEvent
                && ((IdleStateEvent) evt).state().equals(IdleState.READER_IDLE)
                && ctx.channel().attr(AttributeKey.valueOf("HEARTBEAT_PINGED")).get() != null) {

            long t = (Long) ctx.channel().attr(AttributeKey.valueOf("HEARTBEAT_PINGED")).get();


            if (System.currentTimeMillis() - t >= Constant.PING_TIME_OUT * 1000) {
                System.out.println("Time out.So server close the close channel. READER_IDLE  t= " + DateUtils.date2str(t) + "   curTime=" + DateUtils.date2str(System.currentTimeMillis()));
                //ctx.channel().close();
            }
        }

    }


}
